/*
 * lokkup functionalty using getaddrinfo_a() system call
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <sys/socket.h>
#include <sys/types.h>
#include "lookup.h"
#define __USE_GNU
#include <netdb.h>
#undef __USE_GNU

static const char *progname;

static void
usage_help(const int exit_code)
{
    fprintf(stderr, "%s: -l <look up for host> [ -r <reverse lookup for host> ] [ -h <help> ]\n", progname);
    exit(exit_code);
}

void
ip_to_name(const char *hostname, char *ip, int n)
{
    int i,ret;
    char ipaddr[NI_MAXHOST];
    struct gaicb *reqs[n];
    struct addrinfo *res;

    for (i = 0; i < n; i++) {
	reqs[i] = malloc(sizeof(struct gaicb));
	if (reqs[i] == NULL)
	    error("malloc()");
	memset(reqs[i], 0, sizeof(struct gaicb));
	reqs[i]->ar_name = hostname;
    }

    ret = getaddrinfo_a(GAI_WAIT, reqs, 1, NULL);
    if (ret != 0) {
	fprintf(stderr, "getaddrinfo_a() failed %s\n", gai_strerror(ret));
	exit(EXIT_FAILURE);
    }

    for (i = 0; i < n; i++) {    
	ret = gai_error(reqs[0]);
    	if (ret == 0) {
	    res = reqs[0]->ar_result;
	    ret = getnameinfo(res->ai_addr, res->ai_addrlen, ipaddr, sizeof(ipaddr), NULL, 0, 0);
	    if (ret != 0) {
	    	fprintf(stderr, "getnameinfo() failed %s: %m\n", gai_strerror(ret));
	    	exit(EXIT_FAILURE);	
	    }
	}
    }

    strcpy(ip, ipaddr);
}

void
name_to_ip(const char *hostname, char *ip, int n)
{
    int i,ret;
    char ipaddr[NI_MAXHOST];
    struct gaicb *reqs[n];
    struct addrinfo *res;

    for (i = 0; i < n; i++) {
	reqs[i] = malloc(sizeof(struct gaicb));
	if (reqs[i] == NULL)
	    error("malloc()");
	memset(reqs[i], 0, sizeof(struct gaicb));
	reqs[i]->ar_name = hostname;
    }

    ret = getaddrinfo_a(GAI_WAIT, reqs, 1, NULL);
    if (ret != 0) {
	fprintf(stderr, "getaddrinfo_a() failed %s\n", gai_strerror(ret));
	exit(EXIT_FAILURE);
    }

    for (i = 0; i < n; i++) {    
	ret = gai_error(reqs[0]);
    	if (ret == 0) {
	    res = reqs[0]->ar_result;
	    ret = getnameinfo(res->ai_addr, res->ai_addrlen, ipaddr, sizeof(ipaddr), NULL, 0, NI_NUMERICHOST);
	    if (ret != 0) {
	    	fprintf(stderr, "getnameinfo() failed %s: %m\n", gai_strerror(ret));
	    	exit(EXIT_FAILURE);	
	    }
	}
    }

    strcpy(ip, ipaddr);
}

int main(int argc, char **argv)
{
    int optch;
    char *host = NULL;
    char *ip = NULL;
    char ipaddr[NI_MAXHOST];

    progname = strdup(argv[0]);

    if (argc <= 1)
	usage_help(1);

    while ((optch = getopt(argc, argv, "l:r:h")) != -1) {
	switch (optch) {
	    case 'l':
		host = optarg;
		break;
	    case 'r':
		ip = optarg;
		break;
	    case 'h':
		usage_help(0);
		break;
	    default:
		usage_help(1);
		break;
	}
    }

    if (host) {
	name_to_ip(host, ipaddr, 1);
	printf("%s : %s\n",host, ipaddr);
    }

    if (ip) {
	ip_to_name(ip, ipaddr, 1);
	printf("%s : %s\n",ip, ipaddr);
    }


    return 0;
}

